#include "PHLogger.h"
#include "PHLogUser.h"
#include "..\phshared\phshared.h"
#include "ProcessInfo.h"
#include <tlhelp32.h>
#include <boost/thread/thread.hpp>
#include "boost/date_time/posix_time/posix_time.hpp"

using namespace std;
using namespace boost;
using namespace boost::posix_time;

std::map<string,long> PHPaths;

extern CPHLogger logger;

void LoadPathData();
void GetInitialProcessList(long);
void GetAllProcesses()
{
	  HANDLE         hProcessSnap = NULL; 
    PROCESSENTRY32 pe32      = {0}; 
 
    /*  Take a snapshot of all processes in the system. */

    hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 

    if (hProcessSnap == INVALID_HANDLE_VALUE) 
        return ;
 
    /*  Fill in the size of the structure before using it. */

    pe32.dwSize = sizeof(PROCESSENTRY32); 
 
    /*  Walk the snapshot of the processes, and for each process, 
      display information. */

    if (Process32First(hProcessSnap, &pe32)) 
    {         
        while (Process32Next(hProcessSnap, &pe32))
			thread st( &GetInitialProcessList,pe32.th32ProcessID);
    } 
 
    /* Do not forget to clean up the snapshot object. */

    CloseHandle (hProcessSnap); 
    return ;

}/*Win32 end*/

void CPHLogger::StartProcessHistory()
{	
	if(sqlite3_threadsafe()>0)
		PHMessage("SQLite threadsafe");
	else
		PHMessage("SQLite not threadsafe");
	CreateTables();
	//if(!
		ReadUserTable();
	//	PHMessage("No user found. Please create user.");
	LoadPathData();
	//SetupCOM();
	//LoadCommandLines();
	GetAllProcesses();
}

void LoadPathData()
{
	sqlite3 * db=OpenDB();
	sqlite3_stmt* stmt;
	if(sqlite3_prepare(db,"SELECT Directory,ID FROM Paths;",-1,&stmt,NULL)!=SQLITE_OK)
		DBError(sqlite3_errmsg(db),__LINE__,__FILE__);
	while( sqlite3_step(stmt) == SQLITE_ROW )
	{
		const unsigned char* Path=sqlite3_column_text(stmt,0);
		long ID=sqlite3_column_int(stmt,1);
		string p=(char*)Path;
		
		//boost::mutex::scoped_lock psl(paths_mtx);
		PHPaths.insert(pair<string,long>(p,ID));
	}	
	sqlite3_finalize(stmt);
	sqlite3_close(db);
}

map<long,InitialProcess> ipm;
mutex ip_mutex;

void IPThread(InitialProcess ip);

void GetInitialProcessList(long id)
{
	if(id<=4)
		return;
	
	InitialProcess ip;

	
	ip.pi= CProcessInfo(id);	

	/*May have died already*/
	if(ip.pi.Validate()==false)
		return;
	thread st(IPThread,ip);
}
void IPThread(InitialProcess ip)
{
	//string Path;
	ip.pi.GetExecutableImage(true);//Path);
	
	/*Has enough data been gathered*/
	if(ip.pi.Validate()==false)
		return;	
	//cout<<".";
	ip.hProcess=OpenProcess(PROCESS_QUERY_INFORMATION ,FALSE,ip.pi._PId);
	{
		mutex::scoped_lock ipsl(ip_mutex);
		ipm.insert(pair<long,InitialProcess>(ip.pi._PId,ip));
	}
}

extern mutex db_mutex;

/*only record process once ended so this shouldn't be needed
bool CheckUnique(ptime pstart)
{
	mutex::scoped_lock lock(db_mutex);
	stringstream SQL;
	bool _is_already_logged=false;
        SQL<<"SELECT ID FROM Process WHERE CreationTime=JULIANDAY('"<<BoostToSQLite(pstart)<<"');";
 
        sqlite3 *db;
        db=OpenDB();
 
        sqlite3_stmt* stmt;
        if(sqlite3_prepare(db,SQL.str().c_str(),-1,&stmt,NULL)!=SQLITE_OK)
                DBError(sqlite3_errmsg(db),__LINE__,__FILE__);
       
        _is_already_logged=false;
        if( sqlite3_step(stmt) == SQLITE_ROW )
                _is_already_logged=true;
        
        sqlite3_finalize(stmt);
        sqlite3_close(db);
		return _is_already_logged;
}*/

void CPHLogger ::InitialProcessStart(long id)
{
	map<long,InitialProcess>::iterator it=ipm.find(id);
	if(it==ipm.end())
		return;	
	PHMessage("IPS: "+lexical_cast<string>(id));
	it->second.pi.ConvertStartTime();

	/*
	only record process @end
	if(!CheckUnique(it->second.pi.GetStart()))
		it->second.pi.StartEvent();*/

		PHProcessData phpd;
	phpd.hP=it->second.hProcess;
	phpd.time=it->second.pi.GetStart();
		phpd.ProcessID=it->second.pi._ProcessID;
		{
	mutex::scoped_lock log_scoped_lock(processes_mutex);
	/*This needs to be put in the map whether or not the process is in the data*/
	g_clProcesses.insert(pair<long,PHProcessData>(id,phpd));
	}
}